﻿/* Includes ------------------------------------------------------------------*/
#include "SystemTick.h"
#include "Led.h"
#include "Encoder.h"
#include "UART.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DEVICE_ADDR         0x01
#define IDLE_TIME_LIMIT     ( 10 + DEVICE_ADDR*2 )
#define MAX_TX_LEN  32
#define MAX_RX_LEN  32
#define STX         03
#define ETX         04

#define MIN_FRAME_LENGTH    4

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
const U8 CRC_TABLE[256] = {
    0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, 
    0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, 
    0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, 
    0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, 
    0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, 
    0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, 
    0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, 
    0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, 
    0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, 
    0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, 
    0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, 
    0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, 
    0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, 
    0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, 
    0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, 
    0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35, 
};

U8 s_FreeCount = 0;
U8 s_FreeHead  = 0;
U8 s_FreeTail  = 0;
U8 s_FreeIndex[FIFO_TX_SIZE];

U8 s_TxCount = 0;
U8 s_TxHead  = 0;
U8 s_TxTail  = 0;
U8 s_TxIndex[FIFO_TX_SIZE];

sTxBuff s_pTxCmd[FIFO_TX_SIZE];
sTxBuff* s_pPendingIndex = INVALID_INDEX;

u8          s_pTxBuff[MAX_TX_LEN];
__IO u8     s_TxIndex = 0;
u8          s_TxLength = 0;
__IO bool   s_TxSendingFlag = FALSE;

u8          s_pRxBuff[MAX_RX_LEN];
__IO u8     s_RxLength = 0;
__IO bool   s_RxFlag = FALSE;
bool        s_RxWaitNewPackedFlag = TRUE;

#define TIMEOUT_FRAME    5

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8   s_TimeoutCnt = 0;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
void UART_ResetTimeout(void);
u16 UART_GenerateChecksum(u8* pDataIn, u8 iLen);


void SendCmd( U8* iData, U8 iLen)
{
    U8 i, index;
    U8 crc = 0;
    if( true == FreePop(index) )
    {
        for (i=0; i<iLen; ++i)
        {
            s_pTxCmd[index].pData[i] = iData[i];
            crc = GetCrc(s_pTxCmd[index].pData[i], crc);
        }
        s_pTxCmd[index].pData[iLen] = crc;
        s_pTxCmd[index].Length = iLen + 1;

        TxPush(index);
    }
}


bool FreePush( U8 iElement )
{
    if ( s_FreeCount >= FIFO_TX_SIZE ) { return (false); }

    s_FreeIndex[ s_FreeTail++ ] = iElement;
    if ( s_FreeTail == FIFO_TX_SIZE ) { s_FreeTail = 0; }
    ++s_FreeCount;
    return( true );
}


bool FreePop( U8& iElement )
{
    if ( 0 == s_FreeCount ) { return (false); }

    iElement = s_FreeIndex[ s_FreeHead++ ];
    if ( s_FreeHead == FIFO_TX_SIZE ) { s_FreeHead = 0; }
    --s_FreeCount;
    return( true );
}


bool TxPush( U8 iElement )
{
    if ( s_TxCount >= FIFO_TX_SIZE ) { return (false); }

    s_TxIndex[ s_TxTail++ ] = iElement;
    if ( s_TxTail == FIFO_TX_SIZE ) { s_TxTail = 0; }
    ++s_TxCount;
    return( true );
}


bool TxPop( U8& iElement )
{
    if ( 0 == s_TxCount ) { return (false); }

    iElement = s_TxIndex[ s_TxHead++ ];
    if ( s_TxHead == FIFO_TX_SIZE ) { s_TxHead = 0; }
    --s_TxCount;
    return( true );
}


//! UART1 TX Interrupt routine
INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17)
{
    if (s_TxIndex < s_TxLength)
    {
        UART1_SendData8(s_pTxBuff[s_TxIndex++]);
    }
    else
    {
        s_TxSendingFlag = FALSE;
        UART1_ITConfig(UART1_IT_TXE, DISABLE);
    }
}

//! UART1 RX Interrupt routine
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
    u8 data = UART1_ReceiveData8();
    if (TRUE == s_RxWaitNewPackedFlag && DEVICE_ADDR == data)
    {
        s_RxLength = 0;
        s_RxWaitNewPackedFlag = FALSE;
    }
    
    if (MAX_RX_LEN <= s_RxLength)
    {
        s_RxLength = 0;
    }

    s_pRxBuff[s_RxLength++] = data;

    UART_ResetTimeout();
}


//!
U8 GetCrc(U8 iData, U8 iOldCrc)
{
    return (CRC_TABLE[(iData ^ iOldCrc)]);
}

//!
U8 CrcGen(U8* pData, U8 iCnt)
{
    U8 crc = 0;

    while (iCnt)
    {
        crc = CRC_TABLE[(*pData ^ crc)];
        ++pData;
        --iCnt;
    }
    return(crc);
}


//!
void UART_ResetTimeout(void)
{
    s_TimeoutCnt = 0;
}


//!
void UART_TimerInterrupt(void)
{
    if( 0xFF > s_pPendingIndex )
    {
        ++s_pPendingIndex;
        if( IDLE_TIME_LIMIT == s_IdleTimeCnt && IDLE_TIME_LIMIT != s_pPendingIndex )
        {
            UART_Send(s_pTxCmd[s_pPendingIndex].pData, s_pTxCmd[s_pPendingIndex].Length);
        }
    }

    if ( TRUE == s_RxWaitNewPackedFlag ) return;

    if (TIMEOUT_FRAME <= ++s_TimeoutCnt)
    {
        s_RxFlag = TRUE;
        s_RxWaitNewPackedFlag = TRUE;
    }
}


void Memcpy(u8* pDest, u8* pSrc, u8 iLen)
{
    while (iLen--)
    {
        *pDest = *pSrc;
        ++pDest;
        ++pSrc;
    }
}


bool UART_Send(u8* pData, u8 iLen)
{
    if (TRUE == s_TxSendingFlag) return (FALSE);
    Memcpy(s_pTxBuff, pData, iLen);
    s_TxIndex = 0;
    s_TxLength = iLen;
    s_TxSendingFlag = TRUE;
    UART1_ITConfig(UART1_IT_TXE, ENABLE);

    return (TRUE);
}


void UART_Init(void)
{
    U8 i;
    for(i=0; i<FIFO_TX_SIZE; ++i)
    {
        FreePush(i);
    }

    /* De-initializes the UART1 and UART3 peripheral */
    UART1_DeInit();
    /* UART1configuration -------------------------------------------------*/
    /* UART1configured as follow:
    - BaudRate = 9600 baud  
    - Word Length = 8 Bits
    - One Stop Bit
    - No parity
    - Receive and transmit enabled
    - UART1 Clock disabled
    */
    UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO,
        UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);

    /* Enable UART1 Transmit interrupt*/
    UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
    UART1_ITConfig(UART1_IT_TXE, DISABLE);

    SysTick_Registration(&UART_TimerInterrupt);
}


void UART_Reply(u8 iCmd, u8* pData, u8 iLen)
{
    while (TRUE == s_TxSendingFlag);
    s_pTxBuff[0] = DEVICE_ADDR;
    s_pTxBuff[1] = iCmd;
    Memcpy(&s_pTxBuff[2], pData, iLen);
    *((u16*)(&s_pTxBuff[iLen+2])) = UART_GenerateChecksum(s_pTxBuff, iLen+2);
    s_TxIndex = 0;
    s_TxLength = iLen+4;
    s_TxSendingFlag = TRUE;
    UART1_ITConfig(UART1_IT_TXE, ENABLE);
}


u8 HexToAscii(u8 iHex)
{
    u8 temp = iHex & 0x0F;
    if (9 < temp) temp += 7;
    return (temp + '0');
}


u8 AsciiToHex(u8 iAscii)
{
    u8 temp = iAscii & 0x7F;
    if ('9' < temp) temp += 9;
    return (temp & 0x0F);
}


void HexToStrByte(u8* pStr, u8 iHex)
{
    pStr[0] = HexToAscii(iHex >> 4);
    pStr[1] = HexToAscii(iHex & 0x0F);
}

void HexToStrWord(u8* pStr, u16 iHex)
{
    pStr[0] = HexToAscii(iHex >> 12);
    pStr[1] = HexToAscii(iHex >> 8);
    pStr[2] = HexToAscii(iHex >> 4);
    pStr[3] = HexToAscii(iHex & 0x0F);
}

void UART_Processor(u8* pDataIn, u8 iLen)
{
    u8 pBuff[MAX_TX_LEN - 2];

    switch (pDataIn[1])
    {
    case GET_STATUS:
        {
            pBuff[0] = GetSWStatus();
            *((u32*)(&pBuff[1])) = Encoder_GetStatus();
            UART_Reply(GET_STATUS,pBuff,5);
        } break;
   
    case SET_SAMPLE_TIMER:
        {
            Encoder_SetSampleTimer( *((u16*)(&pDataIn[2])) );
            *((u16*)(&pBuff[0])) = Encoder_GetSampleTimer();
            UART_Reply(SET_SAMPLE_TIMER, pBuff, 2);
        } break;
   
    // case 0x03:
        // {
            // pBuff[0]  = 0x01;
            // pBuff[1]  = 0x03;
            // pBuff[2]  = 0x0C;
            // pBuff[3]  = 0x00;
            // pBuff[4]  = 0x03;
            // pBuff[5]  = 0x00;
            // pBuff[6]  = 0x00;
            // pBuff[7]  = 0x00;
            // pBuff[8]  = 0x63;
            // pBuff[9]  = 0x00;
            // pBuff[10] = 0x00;
            // pBuff[11] = 0x00;
            // pBuff[12] = 0x1E;
            // pBuff[13] = 0x01;
            // pBuff[14] = 0x1C;
            // pBuff[15] = 0xAF;
            // pBuff[16] = 0x6D;
            // UART_Send(pBuff,17);
        // } break;
            
    default:
        {
            UART_Reply('N',"",0);
        } break;
    }
}


u16 UART_GenerateChecksum(u8* pDataIn, u8 iLen)
{
    u16 temp;
    u16 crc = 0xFFFF;
    u8 i, j;

    for (i=0; i<iLen; i++)
    {
        crc = ((crc^pDataIn[i]) | 0xFF00) & (crc | 0x00FF);
        for (j=0; j<8; j++)
        {
            temp = crc & 0x0001;
            crc >>= 1;
            if (temp)
            {
                crc ^= 0xA001;
            }
        }
    }

    return (crc);
}


bool UART_FrameIsCorrect(u8* pDataIn, u8 iLen)
{
    u16 crc;
    // kiem tra xem frame co dung voi format quy dinh ko
    if ( (DEVICE_ADDR != pDataIn[0]) || (MIN_FRAME_LENGTH > iLen) ) return (FALSE);

    // kiem tra checksum xem co dung khong
    crc = UART_GenerateChecksum(pDataIn, iLen - 2);
    if ( pDataIn[iLen - 1] == (u8)(crc>>8) && pDataIn[iLen - 2] == (u8)crc ) return (TRUE);
    else return (FALSE);
}


void UART_RunOne(void)
{
    U8 index;
    if( INVALID_INDEX == s_pPendingIndex && true == TxPop(index) && IDLE_TIME_LIMIT <= s_IdleTimeCnt )
    {
        UART_Send(s_pTxCmd[index].pData, s_pTxCmd[index].Length);
        s_pPendingIndex = index;
    }

    if (FALSE == s_RxFlag) return;
    s_RxFlag = FALSE;

    if ( FALSE == UART_FrameIsCorrect(s_pRxBuff, s_RxLength) ) return;

    UART_Processor(s_pRxBuff, s_RxLength);

    // Nhớ thêm phần set s_pPendingIndex = INVALID_INDEX sau khi nhận được reply status.
}
